"""
Borrowed from wxPython XML tree demo and modified.

Ant-man modified on 2008.12
"""

from cn.pigersing.PyShare.utils import encoding
from xml.parsers import expat
import string
import sys


class Element(object):
    '''A parsed XML element'''
    
    def __init__(self, name, attributes=None, cdata=None, children=None):
        'Element constructor'
        # The element's tag name
        self.element_name = name
        # The element's attribute dictionary
        self._attributes = {}
        if attributes :
            for k in attributes.keys() :
                self._attributes[k] = encoding.local2utf8(attributes[k])
        # The element's cdata
        if not cdata:
            cdata = ""
        self.setData(cdata)
        # The element's child element list (sequence)
        if children :
            self._children = children[:]
        else:
            self._children = []
    
    def element_name(): #@NoSelf
        doc = """Docstring""" #@UnusedVariable
       
        def fget(self):
            return encoding.utf82local(self._element_name)
           
        def fset(self, value):
            self._element_name = encoding.local2utf8(value)
           
        return locals()
       
    element_name = property(**element_name())
    
        
    def AddChild(self, element):
        'Add a reference to a child element'
        self._children.append(element)
        
        
    def getAttribute(self, key):
        'Get an attribute value'
        if key not in self._attributes.keys():
            self.setAttribute(key, '')
        return encoding.utf82local(self._attributes.get(key))
    
    
    def setAttribute(self, key, value):
        'Set an attribute value'
        self._attributes[key] = encoding.local2utf8(value)
        
    
    def hasAttribute(self, key):
        
        return self._attributes.has_key(key)
    
    
    def getData(self):
        'Get the cdata'
        return encoding.utf82local(self._cdata)
    
    
    def setData(self, data):
        'Set the cdata'
        self._cdata = encoding.local2utf8(data)
    
        
    def appendDate(self, data):
        'Append the Data'
        self._cdata += encoding.local2utf8(data)
    
        
    def getElements(self, name=''):
        'Get a list of child elements'
        #If no tag name is specified, return the all children
        if not name:
            return self._children
        else:
            # else return only those children with a matching tag name
            name = name.lower()
            return [ element for element in self._children if element.element_name.lower() == name ]
        
    
    def removeElement(self, element):
        
        l = len(self._children)
        for i in xrange(l) :
            if element is self._children[i]: break
        
        # bound check
        if not (element is self._children[i]) :
            return False
        
        del self._children[i]
        
        
    def hasElement(self):
        return len(self._children) > 0
        
        
    def toString(self, level=0, beauty=False):
        
        if beauty :
            if sys.platform[:3] == 'win' :
                newline = '\r\n'
            else:
                newline = '\n'
            intent = " " * 4 * level
        else:
            intent = ""
            newline = ""
            
        ret = intent
        
        ret += "<%s" % self.element_name
        
        # Writes attributes
        for attribute in self._attributes:
            ret += " %s=\"%s\"" % (attribute, self.getAttribute(attribute))
            
        children = ""
        for child in self._children:
            children += child.toString(level + 1, beauty)
        
        value = self.getData()
        if value != "" :
            if  not (value.find(']]>') > - 1):
                value = value.replace('&', '&amp;')
                value = value.replace('<', '&lt;')
                value = value.replace('>', '&gt;')
                value = value.replace("'", '&apos;')
                value = value.replace('"', '&quot;')
            ret += ">" + value + children + ("</%s>%s" % (self.element_name, newline))
        else :
            if children == "":
                ret += "/>" + newline
            else:
                ret += ">" + newline + children + intent + ("</%s>%s" % (self.element_name, newline))
        return ret
    
    
    def __str__(self,):
        
        return self.toString(0, True)
    
    
    def to_xml(self):
        return encoding.local2utf8(self.toString(0))
    
    @staticmethod
    def from_xml_string(src):
        parser = Xml2Obj()
        return  parser.ParseFromString(src)
        
            
class Xml2Obj:
    '''XML to Object'''
    
    def __init__(self):
            
        self.root = None
        self.nodeStack = []


    def ParseFromString(self, src):
        parser = expat.ParserCreate('UTF-8')
        parser.StartElementHandler = self.startElement
        parser.EndElementHandler = self.endElement
        parser.CharacterDataHandler = self.characters
        parser.Parse(src)
        
        return self.root
    

    def Parse(self, filename):
        return self.ParseFromString(open(filename, 'r').read())


    def startElement(self, name, attributes):
        'SAX start element even handler'
        # Instantiate an Element object
        element = Element(name, dict(attributes))
        
        # Push element onto the stack and make it a child of parent
        if len(self.nodeStack) > 0:
            parent = self.nodeStack[ - 1]
            parent.AddChild(element)
        else:
            self.root = element
            
        self.nodeStack.append(element)


    def endElement(self, name):
        'SAX end element event handler'
        self.nodeStack = self.nodeStack[: - 1]


    def characters(self, data):
        'SAX character data event handler'
        if string.strip(data):
            data = data.encode()
            element = self.nodeStack[ - 1]
            element.appendDate(data)


if __name__ == "__main__" :
    
    cont = r'''<?xml version = "1.0" ?>
    <Actions>
        <Action name = "sendFile">
            <State name = "waite" value = "ture" />
            <Property name = "fileSize"><![CDATA[1024]]></Property>
            <Property name = "fileName">dummy</Property>
            <Property name = "fileExt">txt</Property>
        </Action>
        <Action name = "sendFile">
            <State name = "ready" value = "true"/>
        </Action>
    </Actions>'''

    parser = Xml2Obj()
    element = parser.ParseFromString(cont)
    print element.getElements('Action')
    print element
    